package com.pnnd.stream;

import java.nio.*;
import java.nio.charset.Charset;
import java.util.List;

public class BufferView {

    private List<MemorySegment> segmentList;

    private int limit;
    private int mark;
    private int capacity;
    private int startOnSegment;

    private int offset;
    private int currentSegmentIndex;

    public BufferView(List<MemorySegment> segments, int length, int firstSegmentOffset){
        this.mark = this.offset = 0;
        this.currentSegmentIndex = 0;
        this.startOnSegment = firstSegmentOffset;
        this.limit = length;

        this.segmentList = segments;
    }

    public final BufferView reset() {
        int m = mark;
        if (m < 0)
            throw new InvalidMarkException();
        this.offset = m;
        return this;
    }

    public final BufferView clear() {
        this.offset = 0;
        limit = capacity;
        mark = -1;
        return this;
    }

    public final BufferView flip() {
        limit = this.offset;
        this.offset = 0;
        mark = -1;
        return this;
    }

    /**
     * Returns the number of elements between the current position and the
     * limit.
     *
     * @return  The number of elements remaining in this buffer
     */
    public final int remaining() {
        return limit - this.offset;
    }

    /**
     * Tells whether there are any elements between the current position and
     * the limit.
     *
     * @return  <tt>true</tt> if, and only if, there is at least one element
     *          remaining in this buffer
     */
    public final boolean hasRemaining() {
        return this.offset < limit;
    }

    /**
     * Creates a new byte buffer whose content is a shared subsequence of
     * this buffer's content.
     *
     * <p> The content of the new buffer will start at this buffer's current
     * position.  Changes to this buffer's content will be visible in the new
     * buffer, and vice versa; the two buffers' position, limit, and mark
     * values will be independent.
     *
     * <p> The new buffer's position will be zero, its capacity and its limit
     * will be the number of bytes remaining in this buffer, and its mark
     * will be undefined.  The new buffer will be direct if, and only if, this
     * buffer is direct, and it will be read-only if, and only if, this buffer
     * is read-only.  </p>
     *
     * @return The new byte buffer
     */
    
    public BufferView slice() {
        return new BufferView(this.segmentList,this.offset+1,this.startOnSegment);
    }

    /**
     * Creates a new byte buffer that shares this buffer's content.
     *
     * <p> The content of the new buffer will be that of this buffer.  Changes
     * to this buffer's content will be visible in the new buffer, and vice
     * versa; the two buffers' position, limit, and mark values will be
     * independent.
     *
     * <p> The new buffer's capacity, limit, position, and mark values will be
     * identical to those of this buffer.  The new buffer will be direct if,
     * and only if, this buffer is direct, and it will be read-only if, and
     * only if, this buffer is read-only.  </p>
     *
     * @return The new byte buffer
     */
    
    public BufferView duplicate() {
        return new BufferView(this.segmentList,this.limit,this.startOnSegment);
    }

    private int calcCurrentSegmentIndex(){
        return this.calcCurrentSegmentIndex(this.offset);
    }

    private int calcCurrentSegmentIndex(int index){

        int len = this.startOnSegment + index;

        for(int i=0;i<this.segmentList.size();i++){
            MemorySegment segment = this.segmentList.get(i);

            if(len > segment.size()){
                len -= segment.size();
            }else{
                return len;
            }

        }

        throw new IndexOutOfBoundsException();
    }

    public int get(byte[] dst,int index){

        return this.get(dst,index,0,dst.length);
    }

    public int get(byte[] dst){

        return this.get(dst,this.offset);
    }

    public int get(byte[] dst,int index,int off,int len){
        int currentSegmentIndex = this.calcCurrentSegmentIndex(index);

        int position = this.getPosition(index);

        int hasRead = 0;

        if(dst.length+position > this.segmentList.get(currentSegmentIndex).size()){

            int canReadLen = this.segmentList.get(currentSegmentIndex).size() - len - position;

            this.segmentList.get(currentSegmentIndex).get(index,dst,off,canReadLen);

            this.offset += canReadLen;

            hasRead = canReadLen;

            for(int i=currentSegmentIndex;i<this.segmentList.size();i++){
                if(len - hasRead > this.segmentList.get(i).size()){
                    this.segmentList.get(i).get(0,dst,canReadLen,this.segmentList.get(currentSegmentIndex).size());
                    hasRead += this.segmentList.get(i).size();
                }else{
                    this.segmentList.get(i).get(0,dst,canReadLen,len - hasRead);
                    this.offset += len;
                    return len;
                }
            }
        }else{
            this.segmentList.get(currentSegmentIndex).get(index,dst);
            this.offset += dst.length;
            return dst.length;
        }

        this.offset += hasRead;
        return hasRead;
    }

    public int get(byte[] dst,int off,int len){
        return this.get(dst,this.offset,off,len);
    }

    public void put(byte[] src){
        this.put(src,this.offset);
    }

    public void put(byte[] src,int off,int len){
        this.put(src,this.offset,off,len);
    }

    public void put(byte[] src,int index){

    }

    public void put(byte[] src,int index,int off,int len){

        int currentSegmentIndex = this.calcCurrentSegmentIndex(index);

        int position = this.getPosition(index);

        int hasWrite = 0;

        if(len+position > this.segmentList.get(currentSegmentIndex).size()){

            int canReadLen = this.segmentList.get(currentSegmentIndex).size() - len - position;

            this.segmentList.get(currentSegmentIndex).put(index,src,off,canReadLen);

            this.offset += canReadLen;

            hasWrite = canReadLen;

            for(int i=currentSegmentIndex;i<this.segmentList.size();i++){
                if(len - hasWrite > this.segmentList.get(i).size()){
                    this.segmentList.get(i).put(0,src,canReadLen,this.segmentList.get(currentSegmentIndex).size());
                    hasWrite += this.segmentList.get(i).size();
                }else{
                    this.segmentList.get(i).put(0,src,canReadLen,len - hasWrite);
                    return;
                }
            }
        }else{
            this.segmentList.get(currentSegmentIndex).put(index,src,off,len);
            this.offset += len;
        }
    }

    /**
     * Creates a new, read-only byte buffer that shares this buffer's
     * content.
     *
     * <p> The content of the new buffer will be that of this buffer.  Changes
     * to this buffer's content will be visible in the new buffer; the new
     * buffer itself, however, will be read-only and will not allow the shared
     * content to be modified.  The two buffers' position, limit, and mark
     * values will be independent.
     *
     * <p> The new buffer's capacity, limit, position, and mark values will be
     * identical to those of this buffer.
     *
     * <p> If this buffer is itself read-only then this method behaves in
     * exactly the same way as the {@link #duplicate duplicate} method.  </p>
     *
     * @return The new, read-only byte buffer
     */
    
    public BufferView asReadOnlyBuffer() {
        return new ReadOnlyBufferView(this.segmentList,this.offset+1,this.startOnSegment);
    }

    private int getPosition(){
        return this.getPosition(this.offset);
    }

    private int getPosition(int index){
        int len = this.startOnSegment + index;

        for(MemorySegment segment:this.segmentList){
            if(len > segment.size()){
                len -= segment.size();
            }else{
                break;
            }
        }

        return len;
    }

    private void checkIndex(int index){
        if(index >= limit){
            throw new IndexOutOfBoundsException();
        }
    }

    private void checkLen(int offset,int length){
        if(offset + length > this.limit){
            throw new IndexOutOfBoundsException();
        }
    }

    /**
     * Relative <i>get</i> method.  Reads the byte at this buffer's
     * current position, and then increments the position.
     *
     * @return The byte at the buffer's current position
     * @throws BufferUnderflowException If the buffer's current position is not smaller than its limit
     */
    public byte get() {
        byte tmp = this.segmentList.get(currentSegmentIndex).get(this.getPosition());
        this.offset++;
        return tmp;
    }

    /**
     * Relative <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes the given byte into this buffer at the current
     * position, and then increments the position. </p>
     *
     * @param b The byte to be written
     * @return This buffer
     * @throws BufferOverflowException If this buffer's current position is not smaller than its limit
     * @throws ReadOnlyBufferException If this buffer is read-only
     */
    public BufferView put(byte b) {
        this.segmentList.get(currentSegmentIndex).put(this.getPosition(),b);
        this.offset++;
        return this;
    }

    /**
     * Absolute <i>get</i> method.  Reads the byte at the given
     * index.
     *
     * @param index The index from which the byte will be read
     * @return The byte at the given index
     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
     *                                   or not smaller than the buffer's limit
     */
    
    public byte get(int index) {

        return this.segmentList.get(this.currentSegmentIndex).get(this.getPosition(index));
    }

    /**
     * Absolute <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes the given byte into this buffer at the given
     * index. </p>
     *
     * @param index The index at which the byte will be written
     * @param b     The byte value to be written
     * @return This buffer
     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
     *                                   or not smaller than the buffer's limit
     * @throws ReadOnlyBufferException   If this buffer is read-only
     */
    
    public BufferView put(int index, byte b) {
        this.segmentList.get(this.currentSegmentIndex).put(this.getPosition(index),b);
        return this;
    }

    /**
     * Compacts this buffer&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> The bytes between the buffer's current position and its limit,
     * if any, are copied to the beginning of the buffer.  That is, the
     * byte at index <i>p</i>&nbsp;=&nbsp;<tt>position()</tt> is copied
     * to index zero, the byte at index <i>p</i>&nbsp;+&nbsp;1 is copied
     * to index one, and so forth until the byte at index
     * <tt>limit()</tt>&nbsp;-&nbsp;1 is copied to index
     * <i>n</i>&nbsp;=&nbsp;<tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>&nbsp;-&nbsp;<i>p</i>.
     * The buffer's position is then set to <i>n+1</i> and its limit is set to
     * its capacity.  The mark, if defined, is discarded.
     *
     * <p> The buffer's position is set to the number of bytes copied,
     * rather than to zero, so that an invocation of this method can be
     * followed immediately by an invocation of another relative <i>put</i>
     * method. </p>
     *
     *
     *
     * <p> Invoke this method after writing data from a buffer in case the
     * write was incomplete.  The following loop, for example, copies bytes
     * from one channel to another via the buffer <tt>buf</tt>:
     *
     * <blockquote><pre>{@code
     *   buf.clear();          // Prepare buffer for use
     *   while (in.read(buf) >= 0 || buf.position != 0) {
     *       buf.flip();
     *       out.write(buf);
     *       buf.compact();    // In case of partial write
     *   }
     * }</pre></blockquote>
     *
     * @return This buffer
     * @throws ReadOnlyBufferException If this buffer is read-only
     */
    
    public BufferView compact() {
        this.limit = this.offset;
        return this;
    }

    /**
     * Tells whether or not this buffer is read-only.
     *
     * @return <tt>true</tt> if, and only if, this buffer is read-only
     */
    
    public boolean isReadOnly() {
        return false;
    }

    /**
     * Tells whether or not this byte buffer is direct.
     *
     * @return <tt>true</tt> if, and only if, this buffer is direct
     */
    
    public boolean isDirect() {

        boolean result = true;

        for(MemorySegment segment:this.segmentList){
            result = result && segment.isOffHeap();
        }

        return result;
    }

    /**
     * Relative <i>get</i> method for reading a char value.
     *
     * <p> Reads the next two bytes at this buffer's current position,
     * composing them into a char value according to the current byte order,
     * and then increments the position by two.  </p>
     *
     * @return The char value at the buffer's current position
     * @throws BufferUnderflowException If there are fewer than two bytes
     *                                  remaining in this buffer
     */
    
    public char getChar() {

        int tmp = this.getShort();

        return Character.highSurrogate(tmp);
    }

    /**
     * Relative <i>put</i> method for writing a char
     * value&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes two bytes containing the given char value, in the
     * current byte order, into this buffer at the current position, and then
     * increments the position by two.  </p>
     *
     * @param value The char value to be written
     * @return This buffer
     * @throws BufferOverflowException If there are fewer than two bytes
     *                                 remaining in this buffer
     * @throws ReadOnlyBufferException If this buffer is read-only
     */
    public BufferView putChar(char value) {

        int i = value;

        this.put(this.offset++,(byte) (i & 0xff));
        this.put(this.offset++,(byte) (i >>> 8));

        return this;
    }

    /**
     * Absolute <i>get</i> method for reading a char value.
     *
     * <p> Reads two bytes at the given index, composing them into a
     * char value according to the current byte order.  </p>
     *
     * @param index The index from which the bytes will be read
     * @return The char value at the given index
     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
     *                                   or not smaller than the buffer's limit,
     *                                   minus one
     */
    
    public char getChar(int index) {
        int tmp = this.getShort(index);

        return Character.highSurrogate(tmp);
    }

    /**
     * Absolute <i>put</i> method for writing a char
     * value&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes two bytes containing the given char value, in the
     * current byte order, into this buffer at the given index.  </p>
     *
     * @param index The index at which the bytes will be written
     * @param value The char value to be written
     * @return This buffer
     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
     *                                   or not smaller than the buffer's limit,
     *                                   minus one
     * @throws ReadOnlyBufferException   If this buffer is read-only
     */
    
    public BufferView putChar(int index, char value) {

        int i = value;

        this.put(index++,(byte) (i & 0xff));
        this.put(index++,(byte) (i >>> 8));

        return this;
    }

    /**
     * Relative <i>get</i> method for reading a short value.
     *
     * <p> Reads the next two bytes at this buffer's current position,
     * composing them into a short value according to the current byte order,
     * and then increments the position by two.  </p>
     *
     * @return The short value at the buffer's current position
     * @throws BufferUnderflowException If there are fewer than two bytes
     *                                  remaining in this buffer
     */
    
    public short getShort() {
        return (short)((this.get() & 0xff) |
                ((this.get() & 0xff) << 8));
    }

    /**
     * Relative <i>put</i> method for writing a short
     * value&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes two bytes containing the given short value, in the
     * current byte order, into this buffer at the current position, and then
     * increments the position by two.  </p>
     *
     * @param value The short value to be written
     * @return This buffer
     * @throws BufferOverflowException If there are fewer than two bytes
     *                                 remaining in this buffer
     * @throws ReadOnlyBufferException If this buffer is read-only
     */
    
    public BufferView putShort(short value) {
        this.put(this.offset++,(byte) (value & 0xff));
        this.put(this.offset++,(byte) (value >>> 8));
        return this;
    }

    /**
     * Absolute <i>get</i> method for reading a short value.
     *
     * <p> Reads two bytes at the given index, composing them into a
     * short value according to the current byte order.  </p>
     *
     * @param index The index from which the bytes will be read
     * @return The short value at the given index
     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
     *                                   or not smaller than the buffer's limit,
     *                                   minus one
     */
    
    public short getShort(int index) {
        return (short)((this.get(index++) & 0xff) |
                ((this.get(index++) & 0xff) << 8));
    }

    /**
     * Absolute <i>put</i> method for writing a short
     * value&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes two bytes containing the given short value, in the
     * current byte order, into this buffer at the given index.  </p>
     *
     * @param index The index at which the bytes will be written
     * @param value The short value to be written
     * @return This buffer
     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
     *                                   or not smaller than the buffer's limit,
     *                                   minus one
     * @throws ReadOnlyBufferException   If this buffer is read-only
     */
    
    public BufferView putShort(int index, short value) {
        this.put(index++,(byte) (value & 0xff));
        this.put(index++,(byte) (value >>> 8));
        return this;
    }

    /**
     * Relative <i>get</i> method for reading an int value.
     *
     * <p> Reads the next four bytes at this buffer's current position,
     * composing them into an int value according to the current byte order,
     * and then increments the position by four.  </p>
     *
     * @return The int value at the buffer's current position
     * @throws BufferUnderflowException If there are fewer than four bytes
     *                                  remaining in this buffer
     */
    
    public int getInt() {
        return (this.get() & 0xff) |
                ((this.get() & 0xff) << 8) |
                ((this.get()  & 0xff) << 16)|
                ((this.get() & 0xff) << 24);
    }

    /**
     * Relative <i>put</i> method for writing an int
     * value&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes four bytes containing the given int value, in the
     * current byte order, into this buffer at the current position, and then
     * increments the position by four.  </p>
     *
     * @param i The int value to be written
     * @return This buffer
     * @throws BufferOverflowException If there are fewer than four bytes
     *                                 remaining in this buffer
     * @throws ReadOnlyBufferException If this buffer is read-only
     */
    
    public BufferView putInt(int i) {
        this.put(this.offset++,(byte) (i & 0xff));
        this.put(this.offset++,(byte) (i >>> 8));
        this.put(this.offset++,(byte) (i >>> 16));
        this.put(this.offset++,(byte) (i >>> 24));
        return this;
    }

    /**
     * Absolute <i>get</i> method for reading an int value.
     *
     * <p> Reads four bytes at the given index, composing them into a
     * int value according to the current byte order.  </p>
     *
     * @param index The index from which the bytes will be read
     * @return The int value at the given index
     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
     *                                   or not smaller than the buffer's limit,
     *                                   minus three
     */
    
    public int getInt(int index) {
        return (this.get(index++) & 0xff) |
                ((this.get(index++) & 0xff) << 8) |
                ((this.get(index++)  & 0xff) << 16)|
                ((this.get(index) & 0xff) << 24);
    }

    /**
     * Absolute <i>put</i> method for writing an int
     * value&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes four bytes containing the given int value, in the
     * current byte order, into this buffer at the given index.  </p>
     *
     * @param index The index at which the bytes will be written
     * @param i The int value to be written
     * @return This buffer
     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
     *                                   or not smaller than the buffer's limit,
     *                                   minus three
     * @throws ReadOnlyBufferException   If this buffer is read-only
     */
    
    public BufferView putInt(int index, int i) {
        this.put(index++,(byte) (i & 0xff));
        this.put(index++,(byte) (i >>> 8));
        this.put(index++,(byte) (i >>> 16));
        this.put(index++,(byte) (i >>> 24));
        return this;
    }

    /**
     * Relative <i>get</i> method for reading a long value.
     *
     * <p> Reads the next eight bytes at this buffer's current position,
     * composing them into a long value according to the current byte order,
     * and then increments the position by eight.  </p>
     *
     * @return The long value at the buffer's current position
     * @throws BufferUnderflowException If there are fewer than eight bytes
     *                                  remaining in this buffer
     */
    
    public long getLong() {
        return (this.get() & 0xff) |
                ((this.get() & 0xff) << 8) |
                ((this.get()  & 0xff) << 16)|
                ((this.get() & 0xff) << 24)|
                ((this.get() & 0xff) << 32)|
                ((this.get() & 0xff) << 40)|
                ((this.get() & 0xff) << 48)|
                (this.get() & 0xff) << 56;
    }

    /**
     * Relative <i>put</i> method for writing a long
     * value&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes eight bytes containing the given long value, in the
     * current byte order, into this buffer at the current position, and then
     * increments the position by eight.  </p>
     *
     * @param i The long value to be written
     * @return This buffer
     * @throws BufferOverflowException If there are fewer than eight bytes
     *                                 remaining in this buffer
     * @throws ReadOnlyBufferException If this buffer is read-only
     */
    
    public BufferView putLong(long i) {
        this.put(this.offset++,(byte) (i & 0xff));
        this.put(this.offset++,(byte) (i >>> 8));
        this.put(this.offset++,(byte) (i >>> 16));
        this.put(this.offset++,(byte) (i >>> 24));
        this.put(this.offset++,(byte) (i >>> 32));
        this.put(this.offset++,(byte) (i >>> 40));
        this.put(this.offset++,(byte) (i >>> 48));
        this.put(this.offset++,(byte) (i >>> 56));
        return this;
    }

    /**
     * Absolute <i>get</i> method for reading a long value.
     *
     * <p> Reads eight bytes at the given index, composing them into a
     * long value according to the current byte order.  </p>
     *
     * @param index The index from which the bytes will be read
     * @return The long value at the given index
     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
     *                                   or not smaller than the buffer's limit,
     *                                   minus seven
     */
    
    public long getLong(int index) {
        return (this.get(index++) & 0xff) |
                ((this.get(index++) & 0xff) << 8) |
                ((this.get(index++)  & 0xff) << 16)|
                ((this.get(index++) & 0xff) << 24)|
                ((this.get(index++) & 0xff) << 32)|
                ((this.get(index++) & 0xff) << 40)|
                ((this.get(index++) & 0xff) << 48)|
                (this.get(index) & 0xff) << 56;
    }

    /**
     * Absolute <i>put</i> method for writing a long
     * value&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes eight bytes containing the given long value, in the
     * current byte order, into this buffer at the given index.  </p>
     *
     * @param index The index at which the bytes will be written
     * @param value The long value to be written
     * @return This buffer
     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
     *                                   or not smaller than the buffer's limit,
     *                                   minus seven
     * @throws ReadOnlyBufferException   If this buffer is read-only
     */
    
    public BufferView putLong(int index, long value) {
        this.put(index++,(byte) (value & 0xff));
        this.put(index++,(byte) (value >>> 8));
        this.put(index++,(byte) (value >>> 16));
        this.put(index++,(byte) (value >>> 24));
        this.put(index++,(byte) (value >>> 32));
        this.put(index++,(byte) (value >>> 40));
        this.put(index++,(byte) (value >>> 48));
        this.put(index++,(byte) (value >>> 56));
        return this;
    }

    /**
     * Relative <i>get</i> method for reading a float value.
     *
     * <p> Reads the next four bytes at this buffer's current position,
     * composing them into a float value according to the current byte order,
     * and then increments the position by four.  </p>
     *
     * @return The float value at the buffer's current position
     * @throws BufferUnderflowException If there are fewer than four bytes
     *                                  remaining in this buffer
     */
    
    public float getFloat() {
        int tmp = this.getInt();

        return Float.intBitsToFloat(tmp);
    }

    /**
     * Relative <i>put</i> method for writing a float
     * value&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes four bytes containing the given float value, in the
     * current byte order, into this buffer at the current position, and then
     * increments the position by four.  </p>
     *
     * @param value The float value to be written
     * @return This buffer
     * @throws BufferOverflowException If there are fewer than four bytes
     *                                 remaining in this buffer
     * @throws ReadOnlyBufferException If this buffer is read-only
     */
    
    public BufferView putFloat(float value) {
        int i = Float.floatToIntBits(value);

        this.put(this.offset++,(byte) (i & 0xff));
        this.put(this.offset++,(byte) (i >>> 8));
        this.put(this.offset++,(byte) (i >>> 16));
        this.put(this.offset++,(byte) (i >>> 24));
        return this;
    }

    /**
     * Absolute <i>get</i> method for reading a float value.
     *
     * <p> Reads four bytes at the given index, composing them into a
     * float value according to the current byte order.  </p>
     *
     * @param index The index from which the bytes will be read
     * @return The float value at the given index
     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
     *                                   or not smaller than the buffer's limit,
     *                                   minus three
     */
    
    public float getFloat(int index) {

        int tmp = this.getInt(index);

        return Float.intBitsToFloat(tmp);
    }

    /**
     * Absolute <i>put</i> method for writing a float
     * value&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes four bytes containing the given float value, in the
     * current byte order, into this buffer at the given index.  </p>
     *
     * @param index The index at which the bytes will be written
     * @param value The float value to be written
     * @return This buffer
     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
     *                                   or not smaller than the buffer's limit,
     *                                   minus three
     * @throws ReadOnlyBufferException   If this buffer is read-only
     */
    
    public BufferView putFloat(int index, float value) {
        int i = Float.floatToIntBits(value);

        this.put(index++,(byte) (i & 0xff));
        this.put(index++,(byte) (i >>> 8));
        this.put(index++,(byte) (i >>> 16));
        this.put(index++,(byte) (i >>> 24));
        return this;
    }

    /**
     * Relative <i>get</i> method for reading a double value.
     *
     * <p> Reads the next eight bytes at this buffer's current position,
     * composing them into a double value according to the current byte order,
     * and then increments the position by eight.  </p>
     *
     * @return The double value at the buffer's current position
     * @throws BufferUnderflowException If there are fewer than eight bytes
     *                                  remaining in this buffer
     */
    
    public double getDouble() {
        return 0;
    }

    /**
     * Relative <i>put</i> method for writing a double
     * value&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes eight bytes containing the given double value, in the
     * current byte order, into this buffer at the current position, and then
     * increments the position by eight.  </p>
     *
     * @param value The double value to be written
     * @return This buffer
     * @throws BufferOverflowException If there are fewer than eight bytes
     *                                 remaining in this buffer
     * @throws ReadOnlyBufferException If this buffer is read-only
     */
    
    public BufferView putDouble(double value) {
        long i = Double.doubleToRawLongBits(value);

        this.put(this.offset++,(byte) (i & 0xff));
        this.put(this.offset++,(byte) (i >>> 8));
        this.put(this.offset++,(byte) (i >>> 16));
        this.put(this.offset++,(byte) (i >>> 24));
        this.put(this.offset++,(byte) (i >>> 32));
        this.put(this.offset++,(byte) (i >>> 40));
        this.put(this.offset++,(byte) (i >>> 48));
        this.put(this.offset++,(byte) (i >>> 64));
        return this;
    }

    /**
     * Absolute <i>get</i> method for reading a double value.
     *
     * <p> Reads eight bytes at the given index, composing them into a
     * double value according to the current byte order.  </p>
     *
     * @param index The index from which the bytes will be read
     * @return The double value at the given index
     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
     *                                   or not smaller than the buffer's limit,
     *                                   minus seven
     */
    
    public double getDouble(int index) {

        long tmp = this.getLong(index);

        return Double.longBitsToDouble(tmp);
    }

    /**
     * Absolute <i>put</i> method for writing a double
     * value&nbsp;&nbsp;<i>(optional operation)</i>.
     *
     * <p> Writes eight bytes containing the given double value, in the
     * current byte order, into this buffer at the given index.  </p>
     *
     * @param index The index at which the bytes will be written
     * @param value The double value to be written
     * @return This buffer
     * @throws IndexOutOfBoundsException If <tt>index</tt> is negative
     *                                   or not smaller than the buffer's limit,
     *                                   minus seven
     * @throws ReadOnlyBufferException   If this buffer is read-only
     */
    
    public BufferView putDouble(int index, double value) {
        long i = Double.doubleToRawLongBits(value);

        this.put(index++,(byte) (i & 0xff));
        this.put(index++,(byte) (i >>> 8));
        this.put(index++,(byte) (i >>> 16));
        this.put(index++,(byte) (i >>> 24));
        this.put(index++,(byte) (i >>> 32));
        this.put(index++,(byte) (i >>> 40));
        this.put(index++,(byte) (i >>> 48));
        this.put(index++,(byte) (i >>> 64));
        return this;
    }

    public int getLimit() {
        return limit;
    }

    public void setLimit(int limit) {
        this.limit = limit;
    }

    public int getMark() {
        return mark;
    }

    public void setMark(int mark) {
        this.mark = mark;
    }

    public int getCapacity() {
        return capacity;
    }

    public void setCapacity(int capacity) {
        this.capacity = capacity;
    }

    final String readString(String encoding) {
        int i = this.offset;
        int len = 0;
        int maxLen = capacity;

        while ((i < maxLen) && (this.get(i) != 0)) {
            len++;
            i++;
        }

        try {
            byte[] bf = new byte[len];
            this.get(bf);

            return toString(bf, 0, len,encoding);
        } catch (Exception uEE) {
            throw new RuntimeException(uEE);
        } finally {
            this.offset += (len + 1);
        }
    }

    public static String toString(byte[] value, int offset, int length, String encoding) {
        Charset cs = Charset.forName(encoding);

        return cs.decode(ByteBuffer.wrap(value, offset, length)).toString();
    }

    public static String toString(byte[] value, String encoding) {
        Charset cs = Charset.forName(encoding);

        return cs.decode(ByteBuffer.wrap(value)).toString();
    }

    public static String toString(byte[] value, int offset, int length) {
        try {
            Charset cs = Charset.forName("utf-8");

            return cs.decode(ByteBuffer.wrap(value, offset, length)).toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String toString(byte[] value) {
        try {
            Charset cs = Charset.forName("utf-8");

            return cs.decode(ByteBuffer.wrap(value)).toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Read string[$len]
     */
    final String readString(String encoding, int expectedLength) {
        if (this.offset + expectedLength > capacity) {
            //throw SQLError.createSQLException(Messages.getString("ByteArrayBuffer.2"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT, exceptionInterceptor);
        }

        try {
            byte[] bf = new byte[expectedLength];
            this.get(bf);

            return toString(bf, 0, expectedLength,encoding);
        } catch (Exception uEE) {
            throw new RuntimeException(uEE);
        } finally {
            this.offset += expectedLength; // update cursor
        }
    }

    public static void main(String[] args){
        System.out.println(Character.BYTES);
    }
}
